/* Soubor je ulozen v kodovani UTF-8.
 * Kontrola kódování: Příliš žluťoučký kůň úpěl ďábelské ódy. */

package cz.vse.adventura.po1715.cerj117_cermak.hra;

import cz.pecinovsky.english.pojj.adv_framework.game_gui.IListener;
import cz.pecinovsky.english.pojj.adv_framework.game_gui.IObjectG;
import cz.pecinovsky.english.pojj.adv_framework.game_gui.IPlaceG;
import java.awt.Point;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import java.awt.Point;
import java.util.List;

import static cz.vse.adventura.po1715.cerj117_cermak.hra.Předmět.NEZVEDNUTELNÝ;
import static cz.vse.adventura.po1715.cerj117_cermak.hra.Předmět.POUŽITELNÝ;


/*******************************************************************************
 * Instance třídy {@code Místnosti} představují jednotlive "mistnosti"
 * v prochazenem městě. Trida {@code Místnosti} je soucasne schopna vybudovat
 * na zákadě zadných parametrů cele město z jednotlivych mistnosti.
 *
 * @author    Jiří Čermák
 * @version   1.00.000
 */
public enum Místnosti implements IPlaceG
{

    //== HODNOTY VÝČTOVÉHO TYPU ====================================================

    
    náměstí ( new Point(0,0),
        "Ústřední prostor hry, odkud  se dá přesunout do většiny místností.",
        new String[] { "park", "pěšíZóna", "banka", "nádraží", "hospoda" },
        NEZVEDNUTELNÝ+"kašna", NEZVEDNUTELNÝ+"strom", NEZVEDNUTELNÝ+"auto", NEZVEDNUTELNÝ+"babička"
    ),

    hospoda ( new Point(0,0),
        "Vždy je tu něco k pití.",
        new String[] { "sklad", "toalety", "náměstí" },
        "kofola", NEZVEDNUTELNÝ+"hospodský", NEZVEDNUTELNÝ+"stůl", "židle", "klíč"
    ),
    
     toalety ( new Point(0,0),
        "Konečně místo pro úlevu.",
        new String[] { "hospoda" },
        NEZVEDNUTELNÝ+"toaleta", NEZVEDNUTELNÝ+"umyvadlo", NEZVEDNUTELNÝ+"zrcadlo", NEZVEDNUTELNÝ+"ručník", "mýdlo", "toaletníPapír"
   ),

     sklad ( new Point(0,0),
        "Tady je smrad, rychle pryč.",
        new String[] { "hospoda" },
        "bedna", "flaška"
    ),

    banka ( new Point(0,0),
        "Banka je nejblíže z náměstí.",
        new String[] { "náměstí" },
        NEZVEDNUTELNÝ+"sekretářka", NEZVEDNUTELNÝ+"stůl"
    ),

    park ( new Point(0,0),
        "Přeci nebudeš čůrat u stromu. Je tu hodně lidí.",
        new String[] { "náměstí" },
        NEZVEDNUTELNÝ+"strom", NEZVEDNUTELNÝ+"strom", NEZVEDNUTELNÝ+"lavička"
    ),

    pěšíZóna ( new Point(0,0),
        "Moc lidí na to se vyčůrat do rohu. Navíc tohle slušní lidé nedělají.",
        new String[] { "náměstí" },
        NEZVEDNUTELNÝ+"budova", NEZVEDNUTELNÝ+"strom", NEZVEDNUTELNÝ+"obchod"
    ),

    nádraží ( new Point(0,0),
        "Stojí tu vlak směrem na Prahu.",
        new String[] { "náměstí" },
        NEZVEDNUTELNÝ+"vlak", NEZVEDNUTELNÝ+"pokladna", NEZVEDNUTELNÝ+"lavička"
    ),

    zkratka ( new Point(0,0),
        "Zkratka k obhajobě.",
        new String[] {  }
       
    );

  
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

     /** Mapa sloužící k převodu názvu místnosti na odpovídající místnost. */
    private static final Map<String,Místnosti> název2místnost =
                                              new HashMap<String,Místnosti>();

    /** Posluchači očekávající oznámení změně předmětů v místnosti. */
    private static final List<IListener<IPlaceG>> posluchačiPředmětů =
                                    new ArrayList<IListener<IPlaceG>>();

    /** Posluchači očekávající oznámení změně sousedů místnosti. */
    private static final List<IListener<IPlaceG>> posluchačiSousedů =
                                    new ArrayList<IListener<IPlaceG>>();

//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================

     private static Místnosti aktuálníMístnost;



//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================

     //Teprve nyní existují všechny instance i všechny potřebné kontejnery,
    //a proto lze teprve nyní inicializovat sousedy místnosti
    static {
        //Zapamatuji si jména všech místností malými písmeny
        for (Místnosti m : values()) {
            název2místnost.put(m.name().toLowerCase(), m);
        }
        //Jména výchozích sousedů převedu na sousedy a ty uložím
        for (Místnosti m : values()) {
            for (int i=0;   i < m.názvyVýchozíchSousedů.length;   i++) {
                m.výchozíSousedé[i] = název2místnost.get(
                                      m.názvyVýchozíchSousedů[i].toLowerCase());
            }
            m.názvyVýchozíchSousedů = null;  //Už nebudou potřeba
        }
        inicializuj();
    }

//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================

    /** Popis významu a účelu dané místnosti. */
    private final String popis;

    /** Sousedé místnosti na začátku hry. */
    private final Místnosti[] výchozíSousedé;

    /* Předměty v místnosti na počátku hry. */
    private final Předmět[] výchozíPředměty;

    /** Aktuální sousedé dané místnosti. */
    private final Collection<Místnosti> sousedé  = new ArrayList<Místnosti>();

    /** Předměty nacházející se aktuálně v místnosti. */
    private final Collection<Předmět>  předměty = new ArrayList<Předmět>();

     /** Pozice místnosti na plánku hry. */
    private final Point pozice;


  /** potřeba pro funkci z animace. */
 //   private final String[] jménaSousedů;

//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================

    /** Pomocná proměnná používaná v konstruktoru třídy
     *  pro inicializaci pole výchozíSousedé. */
    private String[] názvyVýchozíchSousedů;


//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================

    /***************************************************************************
     * Vrátí odkaz na aktuálni místnost,
     * tj. na místnost, v níž se právě nachází hráč.
     *
     * @return Požadovaný odkaz
     */
    static Místnosti getAktuálníMístnost()
    {
        return aktuálníMístnost;
    }


    /***************************************************************************
     * Nastaví zadanou místnost jako aktuální.
     *
     * @param místnost Nastavovaná aktuální místnost
     */
    static void setAktuálníMístnost(Místnosti místnost) {
        aktuálníMístnost = místnost;
    }


    /***************************************************************************
     * Vrátí odkaz na místnost se zadaným názvem.
     *
     * @param název Název hledané místnosti
     * @return Požadovaný odkaz
     */
    static Místnosti getMístnost(String název)
    {
        Místnosti cil = název2místnost.get(název.toLowerCase());
        return cil;
    }


    /***************************************************************************
     * Vrátí kolekci odkazů na jednotlivé místnosti.
     *
     * @return Požadovaná kolekce
     */
    static Collection<Místnosti> getMístnosti()
    {
        return název2místnost.values();
    }



//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

    /***************************************************************************
     * Inicializuje místnosti do výchozího stavu pro spuštění hry,
     * tj. nastavuje jim výchozí sousedy a výchozí přítomné předměty.
     * Metoda přitom předpokládá, že jsou již přihlášeni všichni posluchači.
     */
    static void inicializuj()
    {
        for (Místnosti m : values()) {
            m.sousedé.clear();
            for (Místnosti soused : m.výchozíSousedé) {
                m.sousedé.add(soused);
            }
            m.předměty.clear();
            for (Předmět predmet : m.výchozíPředměty) {
                m.předměty.add(predmet);
            }
        }
        aktuálníMístnost = náměstí;
    }



//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /***************************************************************************
     * Vytvoří mistnost se zadanými charakteristikami, popisem účelu místnosti,
     * pozicí případného návštěvníka (= pozicí na plánku),
     * seznamem možných sousedů (kam všude se dá z místnosti jít) a
     * seznamem v místnosti se vyskytujících předmětů.
     *
     * @param popis    Popis účelu dané místnosti
     * @param sousedé  Pole s názvy sousedů dané místnosti, tj. s názvy
     *                 místností, do nichž se dá z dané místnosti přejít.
     * @param předměty Názvy předmětů, které se v místnosti vyskytují.
     *                 Konstruktor nechá tyto předměty vyrobit.
     */
    private Místnosti(Point pozice, String popis, String[] sousedé, String... předměty)
    {
        this.pozice = pozice;
        this.popis = popis;
        this.názvyVýchozíchSousedů = sousedé;
        this.výchozíSousedé  = new Místnosti[sousedé.length];
        this.výchozíPředměty = new Předmět [předměty.length];
        for (int i=0;   i < předměty.length;   i++ ) {
            Předmět předmět = new Předmět(předměty[i]);
            výchozíPředměty[i] = předmět;
        }
    }


    /***************************************************************************
     * toto je funkce z animace
     */
//    private Místnosti(String popis, String [] sousedé, String... předměty )
//    {
//        this.popis = popis;
//        jménaSousedů = sousedé;
//
//        for ( String název : předměty ) {
//            Předmět předmět = (Character.isUpperCase(název.charAt(0)))
//                            ? new Předmět(false, název)
//                            : new Předmět(true, název);
//            this.předměty.add(předmět);
//        }
//    }



//== ABSTRAKTNÍ METODY =========================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ INSTANCÍ =====================================

     /***************************************************************************
     * Vrati název mistnosti.
     *
     * @return Nazev mistnosti
     */
    @Override
    public String getName()
    {
        return name();
    }


    /***************************************************************************
     * Vrati popis mistnosti, ktery danou mistnost strucne charakterizuje.
     *
     * @return Pozadovany popis
     */
    @Override
    public String getDescription()
    {
        return popis;
    }


    /***************************************************************************
     * Vrati kolekci predmetu nachazejicich se v dane mistnosti.
     *
     * @return Pozadovana kolekce
     */
    @Override
    public Collection<? extends IObjectG> getObjects()
    {
        return předměty;
    }


    /***************************************************************************
     * Vrati kolekci mistnosti, do nichz je mozno se z teto mistnosti presunout.
     *
     * @return Pozadovana kolekce
     */
    @Override
    public Collection<Místnosti> getNeighbors()
    {
        return sousedé;
    }


//== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ========================================

     /***************************************************************************
     * Vrátí název dané instance.
     *
     * @return Nazev instance
     */
    @Override
    public String toString()
    {
        return name();
    }


    /***************************************************************************
     * Odlozi zadany predmet v mistnosti.
     *
     * @param  predmet odkladany v mistnosti
     * @return {@code true} pokud byl predmet do mistnosti vlozen
     */

    void polož( Předmět predmet ) {
        předměty.add( predmet );
    }

    public void pridejSouseda(Místnosti mistnost)
    {
        sousedé.add(mistnost);
    }


    /***************************************************************************
     * Odebere predmet zadaneho nazvu z mistnosti.
     * Odebrat je mozne pouze zvednutelné předměty.
     *
     * @param název Nazev odebiraneho predmetu
     * @return Byl-li předmět z místnosti odebrán, vrátí tento předmět.
     *         Nebyl-li předmět zvednutelný, vrátí předmět {@link TIHA}.
     *         Nebyl-li v místnosti požadovaný předmět, vrátí {@code null}.
     */
    Předmět zvedni(String nazev)
    {
        String jmeno;
        Předmět nasel = null;
        for( Předmět predmet : předměty ) {
            jmeno = predmet.getName();
            if (jmeno.equalsIgnoreCase( nazev ))  {
                if (predmet.isTransportable())  {
                    předměty.remove(predmet);
                    nasel = predmet;
                } else {
                    nasel = Předmět.PEVNÁ;
                }
                break;
            }
        }
        return nasel;
    }



 /***************************************************************************
     * Vrátí pozici místnosti na plánu hry,
     * presněji pozici hráče nacházejícícho se v dané místnosti.
     * Na této pozici bude hráč při pobytu v dané místnosti zobrazen.
     *
     * @return Požadovaná pozice
     */
    @Override
    public Point getPosition() {
        return pozice;
    }



//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== INTERNÍ DATOVÉ TYPY =======================================================
//== TESTOVACÍ METODY A TŘÍDY ==================================================
//
//     /***************************************************************************
//      * Testovací metoda.
//      */
//     public static void test()
//     {
//         Místnosti instance = new Místnosti();
//     }
//     /** @param args Parametry příkazového řádku - nepoužívané. */
//     public static void main(String[] args)  {  test();  }
}
